﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Prsrp
{
    public class BaseMap
    {
        // Ressources
        private List<BaseCollectable> mtabCollectables    = new List<BaseCollectable>();
        private List<BaseHero>        mtabCharacters      = new List<BaseHero>();
        private List<BaseEnemy>       mtabEnemies         = new List<BaseEnemy>();
        private List<BaseProjectile>  mtabHeroProjectiles = new List<BaseProjectile>();
        private List<BaseParticle>    mtabParticles       = new List<BaseParticle>();
        private List<BaseDisplayable> mtabChipSets        = new List<BaseDisplayable>();

        // Ressources public exposures
        /// <summary>
        /// Collection of all the characters in the map.
        /// </summary>
        public List<BaseHero> Characters
        {
            get { return mtabCharacters; }
        }
        /// <summary>
        /// Collection of all the enemies in the map.
        /// </summary>
        public List<BaseEnemy> Enemies
        {
            get { return mtabEnemies; }
        }
        /// <summary>
        /// Collection of all the collectables in the map.
        /// </summary>
        public List<BaseCollectable> Collectables
        {
            get { return mtabCollectables; }
        }

        // Function to redefine
        public virtual void LoadRessources()
        {
            throw new NotImplementedException();   
        }

        #region Update Functions & Methods

        /// <summary>
        /// Iterate through each objects in a list and delete thoses where CanDispose() is true.
        /// </summary>
        /// <param name="_tabAssets">A list of objects who inherith from <typeparamref name="BaseStateMachine"/>.</param>
        private void CollectGarbage<T>(List<T> _tabAssets) where T : BaseStateMachine
        {
            for (int iCurAsset = 0; iCurAsset < _tabAssets.Count; ++iCurAsset)
            {
                BaseStateMachine pCurAsset = _tabAssets[iCurAsset];
                if (pCurAsset.CanDispose())
                {
                    _tabAssets.RemoveAt(iCurAsset);
                    --iCurAsset;
                }
            }
        }

        /// <summary>
        /// Call Update() on each ressources in <paramref name="_tabAssets"/>.
        /// Collect garbage after..
        /// </summary>
        /// <param name="_tabAssets">A list of objects that herith from <typeparamref name="BaseStateMachine"/></param>
        private void UpdateRessource<T>(List<T> _tabAssets) where T : BaseAsset
        {
            foreach (T pCurAsset in _tabAssets)
            {
                pCurAsset.Update();
            }
            CollectGarbage(_tabAssets);
        }

        /// <summary>
        /// Call UpdateRessource() on each ressources.
        /// </summary>
        private void UpdateRessources()
        {
            UpdateRessource(mtabEnemies);
            UpdateRessource(mtabCharacters);
            UpdateRessource(mtabCollectables);
            UpdateRessource(mtabHeroProjectiles);
            UpdateRessource(mtabParticles);
        }

        /// <summary>
        /// Call HandleCollision between each ressources who inherith from <typeparamref name="BasePhysic"/>.
        /// </summary>
        private void HandleCollisions()
        {
            foreach (BaseHero pCurHero in mtabCharacters)
            {
                foreach (BaseEnemy pCurEnemy in mtabEnemies)
                {
                    pCurHero.HandleCollision(pCurEnemy);
                }
                foreach (BaseChipset pCurChipset in mtabChipSets)
                {
                    pCurHero.HandleCollision(pCurChipset);
                }
            }
        }

        /// <summary>
        /// Call HandlePhysics() on each ressources who inherith from <typeparamref name="BasePhysic"/>.
        /// </summary>
        private void HandlePhysics()
        {
            foreach (BaseHero pCurHero in mtabCharacters)
            {
                pCurHero.HandlePhysics();
            }
            foreach (BaseEnemy pCurEnemy in mtabEnemies)
            {
                pCurEnemy.HandlePhysics();
            }
        }

        /// <summary>
        /// Call all update functions on each ressources.
        /// </summary>
        public void Update()
        {
            UpdateRessources();
            HandleCollisions();
            HandlePhysics();
        }

        #endregion

        #region Draw Functions & Methods

        /// <summary>
        /// Call Draw() on each ressource who inherith from <typeparamref name="BaseDisplayable"/>.
        /// </summary>
        /// <param name="_tabAssets">A list of objects who inherith from <typeparamref name="BaseDisplayable"/>.</param>
        private void DrawDisplayable<T>(List<T> _tabAssets) where T : BaseDisplayable
        {
            foreach (BaseDisplayable pCurDisplayable in _tabAssets)
            {
                pCurDisplayable.Draw();
                if (GameGlobals.ShowCollisions)
                {
                    DrawingFunctions.DrawRectangle(pCurDisplayable.GetHitBox(), DrawingColors.Red);
                }
            }
        }

        /// <summary>
        /// Call all draw functions on each ressources.
        /// </summary>
        public void Draw()
        {
            DrawDisplayable(mtabChipSets);
            DrawDisplayable(mtabCharacters);
            DrawDisplayable(mtabCollectables);
            DrawDisplayable(mtabHeroProjectiles);
            DrawDisplayable(mtabEnemies);
            DrawDisplayable(mtabParticles);
        }

        #endregion

        #region Ressource Loading Functions

        public void AddHero(BaseHero _pNewHero)
        {
            mtabCharacters.Add(_pNewHero);
        }

        public void AddEnemy(BaseEnemy _pNewEnemy)
        {
            mtabEnemies.Add(_pNewEnemy);
        }

        public void AddCollectable(BaseCollectable _pNewCollectable)
        {
            mtabCollectables.Add(_pNewCollectable);
        }

        public void AddProjectile(BaseProjectile _pNewProjectile)
        {
            mtabHeroProjectiles.Add(_pNewProjectile);
        }

        public void AddParticle(BaseParticle _pNewParticle)
        {
            mtabParticles.Add(_pNewParticle);
        }

        public void AddChipSet(BaseDisplayable _pNewChipset)
        {
            mtabChipSets.Add(_pNewChipset);
        }

        #endregion

        /// <summary>
        /// Default constructor.
        /// </summary>
        public BaseMap()
        {
            LoadRessources();
        }
    }
}
